#include "stdafx.h"
#include "AttributeFunc.h"
#include "AttributeManager.h"

#include "xKernel/IxElement.h"

void release_attri_data(LPATTRIBUTEDATA& pData)
{
    delete pData->m_pCallMethod;
    pData->m_pCallMethod = NULL;

    delete pData;
    pData = NULL;
}

CxAttributeManager::CxAttributeManager()
{}

CxAttributeManager::~CxAttributeManager()
{}

HRESULT CxAttributeManager::RegisterAttribute(BSTR bsName, INT nType, IID iid, UINT unMethod)
{
    UINT key = ::xBase::Time33HashMethod(bsName);

    if (-1 != key)
    {
        ATTRIMAPIT it = m_mapAttribute.find(key);

        CxCallMethod* pCallMethod = NULL;

        switch (nType)
        {
        case E_ATTRI_INT:
            {
                pCallMethod = new CxCallMethodINT;
            }
            break;
        case E_ATTRI_BOOL:
            {
                pCallMethod = new CxCallMethodBOOL;
            }
            break;
        case E_ATTRI_BYTE:
            {
                pCallMethod = new CxCallMethodBYTE;
            }
            break;
        case E_ATTRI_SIZE:
            {
                pCallMethod = new CxCallMethodSIZE;
            }
            break;
        case E_ATTRI_POINT:
            {
                pCallMethod = new CxCallMethodRECT;
            }
            break;
        case E_ATTRI_RECT:
            {
                pCallMethod = new CxCallMethodRECT;
            }
            break;
        case E_ATTRI_COLORREF:
            {
                pCallMethod = new CxCallMethodCOLORREF;
            }
            break;
        case E_ATTRI_BSTR:
            {
                pCallMethod = new CxCallMethodBSTR;
            }
            break;
        case E_ATTRI_IXDRAW:
            {
                pCallMethod = new CxCallMethodIxDraw;
            }
            break;
        case E_ATTRI_ALIGNMENT:
            {
                pCallMethod = new CxCallMethodAlignment;
            }
            break;
        default:
            ATLASSERT(!L"the attribute type is not supported!!!");
            break;
        }

        if (it == m_mapAttribute.end())
        {
            LPATTRIBUTEDATA pData = new ATTRIBUTEDATA;
            pData->m_uuid = iid;
            pData->m_pMethod = unMethod;
            pData->m_pNext = NULL;
            pData->m_pCallMethod = pCallMethod;

            m_mapAttribute.insert(std::make_pair(key, pData));
        }
        else
        {
            //ATLASSERT(!L"attribute conflict!!!");

            LPATTRIBUTEDATA& pCurData = it->second;

            LPATTRIBUTEDATA pData = new ATTRIBUTEDATA;
            pData->m_uuid = iid;
            pData->m_pMethod = unMethod;
            pData->m_pNext = pCurData->m_pNext;
            pData->m_pCallMethod = pCallMethod;

            pCurData->m_pNext = pData;
        }

        return S_OK;
    }

    return E_FAIL;
}

HRESULT CxAttributeManager::UnregisterAttribute(BSTR bsName, IID iid)
{
    UINT key = ::xBase::WCHAR2INT(bsName);

    if (-1 == key)
    {
        return E_FAIL;
    }


    ATTRIMAPIT it = m_mapAttribute.find(key);

    if (it == m_mapAttribute.end())
    {
        return E_FAIL;
    }

    LPATTRIBUTEDATA pData = it->second;

    if (!pData)
    {
        ATLASSERT(!L"there are abnormal data in Attribute Manager!!!");
        return E_FAIL;
    }

    HRESULT hRet = E_FAIL;

    if (pData->m_uuid == iid)
    {
        if (pData->m_pNext)
        {
            it->second = pData->m_pNext;
        }
        else
        {
            m_mapAttribute.erase(it);
        }

        release_attri_data(pData);

        hRet = S_OK;
    }
    else
    {
        pData = pData->m_pNext;
        while (pData)
        {
            if (pData->m_uuid == iid)
            {
                release_attri_data(pData);

                hRet = S_OK;

                break;
            }
        }
    }

    return hRet;
}

HRESULT CxAttributeManager::SetAttribute(IUnknown* pUnk, IxPairVec* pVec)
{
    if (!pUnk || !pVec)
    {
        return E_INVALIDARG;
    }

    INT nCount = 0;
    pVec->GetCount(&nCount);

    for (int i = 0; i < nCount; ++i)
    {
        CComBSTR bsName;
        pVec->GetName(i, &bsName);

        UINT key = ::xBase::Time33HashMethod(bsName);

        if (-1 != key)
        {
            ATTRIMAPIT it = m_mapAttribute.find(key);
            if (it != m_mapAttribute.end())
            {
                LPATTRIBUTEDATA pData = it->second;

                VOID* pTarget = NULL;

                while (pData)
                {
                    if (pData->m_pCallMethod)
                    {
                        CComPtr<IUnknown> spUnk;
                        HRESULT hRet = pUnk->QueryInterface(pData->m_uuid, (void**)&spUnk);

                        if (SUCCEEDED(hRet) && spUnk)
                        {
                            pData->m_pCallMethod->CallMethod(PointerToUINT(spUnk.p), pData->m_pMethod, i, pVec);
                            break;
                        }
                    }

                    pData = pData->m_pNext;
                }
            }
            else
            {
                ATLASSERT(!L"the attribute not supported!!!");
            }
        }
    }

    return S_OK;
}
